home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / smtpcli.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  34KB  |  1,378 lines

  1. /*
  2.  *    CLIENT routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13.  
  14. /****************************************************************************
  15. *    $Id: smtpcli.c 1.18 94/01/04 14:10:21 ROOT_DOS Exp $
  16. *    29 May 92    1.2    GT        mailroute (): use gateway if defined.
  17. *    02 Jun 92    1.3    GT        Add "smtp wait" and timeout on connect () call
  18. *                                   in smtp_send ().
  19. *    04 Jun 92    1.4    GT        Make smtptick () a separate process.
  20. *    05 Jun 92    1.5    GT        Timeout on connect () to Gateway.
  21. *    26 Jun 92            Paul@wolf.demon.co.uk Fixed routing for internal
  22. *                                  email (doesn't go via the external gateway)
  23. *    13 Jul 92    1.7    GT        Remove 1.6 changes.
  24. *    05 Aug 92            amc@beryl.demon.co.uk changed printfs to tprintf
  25. *    27 Aug 92   1.10  mt@kram.demon.co.uk added smtp separator
  26. *    Dec 92                mt@kram.org don't use gateway for any mail MXed via
  27. *                                    us. Add delay channel for local mail
  28. *                                    Add smtp beep on|off
  29. *    19 Apr 93    1.16    GT        If newproc () fails, reset tick flag.
  30. *    08 May 93    1.17    GT        Fix warnings.
  31. *                                    Fix "smtp list".
  32. *                            IAY     Fix dot transparency as per RFC 821.
  33. *    07 Nov 93    1.18    GT        Verbose: show "sending" progress.
  34. *                                    mailroute (): cope with domain literals.
  35. *
  36. *  ST NOS Version by David Nash - dnash@chaos.demon.co.uk
  37. *
  38. *  __stdargs  - smtp_send, smtptick_body
  39. *  dosmtplist - call statx to fix path seperator
  40. *
  41. ****************************************************************************/
  42.  
  43. #include <stdio.h>
  44. #include <fcntl.h>
  45. #ifdef ATARI
  46. #include <ext.h>
  47. #include <sys/types.h>
  48. #include <unistd.h>
  49. #endif
  50. #include <time.h>
  51. #include <setjmp.h>
  52. #ifdef UNIX
  53. #include <sys/types.h>
  54. #endif
  55. #ifdef    AMIGA
  56. #include <stat.h>
  57. #else
  58. #include <sys/stat.h>
  59. #endif
  60. #ifdef    __TURBOC__
  61. #include <dir.h>
  62. #include <io.h>
  63. #endif
  64. #include "global.h"
  65. #include <stdarg.h>
  66. #include "config.h"
  67. #include "domain.h"
  68. #include "mbuf.h"
  69. #include "cmdparse.h"
  70. #include "proc.h"
  71. #include "socket.h"
  72. #include "timer.h"
  73. #include "netuser.h"
  74. #include "smtp.h"
  75. #include "dirutil.h"
  76. #include "commands.h"
  77. #include "session.h"
  78. #include "ip.h"
  79.  
  80. static struct timer Smtpcli_t;
  81. static int32 Gateway;
  82. static int32 Delaytime = 0;
  83. int   near smtpverbose = 1;
  84. char *near smtp_separator = NULL;
  85. int   near are_we_an_mx;
  86.  
  87. static unsigned short Smtptrace = 0;    /* used for trace level */
  88. static int dosmtptrace __ARGS ((int argc, char *argv[], void *p));
  89.  
  90. static unsigned short Smtpmaxcli = MAXSESSIONS;    /* the max client connections
  91.                                                  * allowed */
  92. static int Smtpsessions = 0; /* number of client connections currently open */
  93. static int Smtpbatch;
  94. int near Smtpmode = 0;
  95. int near Smtpbeep = 0;
  96.  
  97. int32 near connect_wait_val = 60000L;        /* default connection timeout         */
  98.  
  99. static struct smtpcli *cli_session[MAXSESSIONS];        /* queue of client
  100.                                                          * sessions  */
  101.  
  102. static void del_job __ARGS ((struct smtp_job * jp));
  103. static void del_session __ARGS ((struct smtpcli * cb));
  104. static int dogateway __ARGS ((int argc, char *argv[], void *p));
  105. static int doseparator __ARGS ((int argc, char *argv[], void *p));
  106. static int dosmtpmaxcli __ARGS ((int argc, char *argv[], void *p));
  107. static int dotimer __ARGS ((int argc, char *argv[], void *p));
  108. static int dodelay __ARGS ((int argc, char *argv[], void *p));
  109. static int dowait __ARGS ((int argc, char *argv[], void *p));
  110. static int dosmtpkill __ARGS ((int argc, char *argv[], void *p));
  111. static int dosmtplist __ARGS ((int argc, char *argv[], void *p));
  112. static int dobatch __ARGS ((int argc, char *argv[], void *p));
  113. static int dobeep __ARGS ((int argc, char *argv[], void *p));
  114. static void execjobs __ARGS ((void));
  115. static int getresp __ARGS ((struct smtpcli * ftp, int mincode));
  116. static void logerr __ARGS ((struct smtpcli * cb, char *line));
  117. static struct smtpcli *lookup __ARGS ((int32 destaddr));
  118. static struct smtpcli *newcb __ARGS ((void));
  119. static int next_job __ARGS ((struct smtpcli * cb));
  120. static void retmail __ARGS ((struct smtpcli * cb));
  121. static void sendcmd __ARGS ((struct smtpcli * cb, char *fmt,...));
  122. static int smtpsendfile __ARGS ((struct smtpcli * cb));
  123. static int setsmtpmode __ARGS ((int argc, char *argv[], void *p));
  124. static struct smtp_job *setupjob __ARGS ((struct smtpcli * cb, char *id, char *from));
  125. static void __stdargs smtp_send __ARGS ((int unused, void *cb1, void *p));
  126. static int smtpkick __ARGS ((int argc, char *argv[], void *p));
  127. static void __stdargs smtptick_body __ARGS ((int unused, void *t, void *p));
  128. static int doverbose __ARGS ((int argc, char *argv[], void *p));
  129. static int should_enter_delay __ARGS ((struct smtpcli * cb));
  130. static int explock __ARGS ((char *dir, char *pre, char *suf, int32 age));
  131.  
  132. static struct cmds Smtpcmds[] = {
  133.     {"batch",             dobatch,         0, 0, NULLCHAR},
  134.     {"beep",             dobeep,             0, 0, NULLCHAR},
  135.     {"delay",             dodelay,         0, 0, NULLCHAR},
  136.     {"gateway",         dogateway,         0, 0, NULLCHAR},
  137.     {"kick",             smtpkick,         0, 0, NULLCHAR},
  138.    {"kill",             dosmtpkill,     0, 2, "kill <jobnumber>"},
  139.     {"list",             dosmtplist,     0, 0, NULLCHAR},
  140.     {"maxclients",     dosmtpmaxcli,     0, 0, NULLCHAR},
  141.     {"mode",             setsmtpmode,     0, 0, NULLCHAR},
  142.     {"separator",         doseparator,     0, 0, NULLCHAR},
  143.     {"timer",             dotimer,         0, 0, NULLCHAR},
  144.     {"trace",             dosmtptrace,     0, 0, NULLCHAR},
  145.     {"wait",             dowait,             0, 0, NULLCHAR},
  146.     {"verbose",         doverbose,         0, 0, NULLCHAR},        /* Actually for Server */
  147.     {NULLCHAR},
  148. };
  149.  
  150.  
  151. int dosmtp(int argc, char *argv[], void *p)
  152. {
  153.     return subcmd (Smtpcmds, argc, argv, p);
  154. }
  155.  
  156.  
  157. static int dobatch(int argc, char *argv[], void *p)
  158. {
  159.     return setbool (&Smtpbatch, "SMTP batching", argc, argv);
  160. }
  161.  
  162.  
  163. static int dobeep(int argc, char *argv[], void *p)
  164. {
  165.     return setbool (&Smtpbeep, "SMTP beep on delivery", argc, argv);
  166. }
  167.  
  168.  
  169. static int dosmtpmaxcli(int argc, char *argv[], void *p)
  170. {
  171.     return setshort (&Smtpmaxcli, "Max clients", argc, argv);
  172. }
  173.  
  174.  
  175. static int setsmtpmode(int argc, char *argv[], void *p)
  176. {
  177.     if (argc < 2) {
  178.         tprintf ("smtp mode: %s\n", (Smtpmode & QUEUE) ? "queue" : "route");
  179.     }
  180.     else {
  181.         switch (*argv[1]) {
  182.             case 'q':
  183.                 Smtpmode |= QUEUE;
  184.                 break;
  185.             case 'r':
  186.                 Smtpmode &= ~QUEUE;
  187.                 break;
  188.             default:
  189.                 tprintf ("Usage: smtp mode [queue | route]\n");
  190.                 break;
  191.         }
  192.     }
  193.  
  194.     return 0;
  195. }
  196.  
  197.  
  198. static int dogateway(int argc, char *argv[], void *p)
  199. {
  200.     int32 n;
  201.  
  202.     if (argc < 2)
  203.         tprintf ("%s\n", inet_ntoa (Gateway));
  204.     else
  205.     if ((n = resolve (argv[1])) == 0) {
  206.         tprintf (Badhost, argv[1]);
  207.         return 1;
  208.     }
  209.     else
  210.         Gateway = n;
  211.     log(-1, "dogateway: resolve gateway = %x ", (void *)Gateway); /* DEBUG */    
  212.  
  213.     return 0;
  214. }
  215.  
  216.  
  217. static int doseparator(int argc, char *argv[], void *p)
  218. {
  219.     int i;
  220.     char *t;
  221.  
  222.     if (argc < 2) {
  223.         if (smtp_separator) {
  224.             log(-1, "doseparator: free smtp_separator = %x ",(void *)smtp_separator); /* DEBUG */
  225.             free(smtp_separator);
  226.         }
  227.  
  228.         smtp_separator = NULL;
  229.     }
  230.     else {
  231.         t = malloc(81);
  232.         log(-1, "doseperator: malloc t = %x ", (void *)t);  /* DEBUG */
  233.         if (t == NULL)
  234.             return 1;
  235.  
  236.         t[0] = '\0';
  237.         for (i = 1; i < argc; i++)    {
  238.             strcat (t, argv[i]);
  239.             if (i < (argc - 1))
  240.                 strcat (t, " ");
  241.  
  242.         }
  243.         if ((smtp_separator = malloc(strlen (t) + 1)) == NULL)    {
  244.             log(-1, "doseperator: free t = %x ", (void *)t);  /* DEBUG */
  245.             free(t);
  246.             return 1;
  247.         }
  248.         log(-1, "doseperator: malloc smtp_separator = %x ", (void *)smtp_separator); /* DEBUG */
  249.  
  250.         strcpy(smtp_separator, t);
  251.         log(-1, "doseperator: free t = %x ", (void *)t);  /* DEBUG */
  252.         free(t);
  253.     }
  254.  
  255.     return 0;
  256. }
  257.  
  258.  
  259. static int dosmtptrace(int argc, char *argv[], void *p)
  260. {
  261.     return setshort (&Smtptrace, "SMTP tracing", argc, argv);
  262. }
  263.  
  264.  
  265. /* list jobs wating to be sent in the mqueue */
  266.  
  267. static int dosmtplist (int argc, char *argv[], void *p)
  268. {
  269.     char tstring[80];
  270.     char line[20];
  271.     char host[LINELEN];
  272.     char to[LINELEN];
  273.     char from[LINELEN];
  274.     char *cp;
  275.     char status;
  276.     struct stat stbuf;
  277.     struct tm *tminfo;
  278.     FILE *fp;
  279.  
  280.     int    statx(const char *, struct stat *);
  281.  
  282.     Current->flowmode = 1;                         /* Enable the more mechanism */
  283.     tprintf ("S     Job    Size Date  Time  Host                 From\n");
  284.     filedir (Mailqueue, 0, line);
  285.     while (line[0] != '\0')    {
  286.         (void) sprintf (tstring, "%s/%s", Mailqdir, line);
  287.         if ((fp = fopen (tstring, READ_TEXT)) == NULLFILE) {
  288.             tprintf ("Can't open %s: %s\n", tstring, sys_errlist[errno]);
  289.             pwait (NULL);
  290.             filedir (Mailqueue, 1, line);
  291.             continue;
  292.         }
  293.  
  294.         if ((cp = strrchr (line, '.')) != NULLCHAR)
  295.             *cp = '\0';
  296.  
  297.         (void) sprintf (tstring, "%s/%s.lck", Mailqdir, line);
  298.         if (access (tstring, 0))
  299.             status = ' ';
  300.         else
  301.             status = 'L';
  302.  
  303.         /* Now see if it's in delay */
  304.         if (status == ' ') {
  305.             sprintf (tstring, "%s/%s.dly", Mailqdir, line);
  306.             if (!access (tstring, 0))
  307.                 status = 'D';
  308.  
  309.         }
  310.  
  311.         (void) sprintf (tstring, "%s/%s.txt", Mailqdir, line);
  312.         if (statx (tstring, &stbuf) == -1) { /* ATARI statx to fix path sep */ 
  313.             tprintf ("Can't stat %s: %s\n", tstring, sys_errlist[errno]);
  314.             pwait (NULL);
  315.             filedir (Mailqueue, 1, line);
  316.             continue;
  317.         }
  318.  
  319.         tminfo = localtime (&stbuf.st_ctime);
  320.         fgets (host, sizeof (host), fp);
  321.         rip (host);
  322.         fgets (from, sizeof (from), fp);
  323.         rip (from);
  324.         tprintf ("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n      ",
  325.                  status, line, stbuf.st_size,
  326.                  tminfo->tm_mon + 1,
  327.                  tminfo->tm_mday,
  328.                  tminfo->tm_hour,
  329.                  tminfo->tm_min,
  330.                  host, from);
  331.         while (fgets (to, sizeof (to), fp) != NULLCHAR) {
  332.             rip (to);
  333.             tprintf ("%s ", to);
  334.         }
  335.  
  336.         tprintf ("\n");
  337.         (void) fclose (fp);
  338.         pwait (NULL);
  339.         filedir (Mailqueue, 1, line);
  340.     }
  341.  
  342.     Current->flowmode = 0;
  343.     return 0;
  344. }
  345.     
  346.  
  347. /*  dosmtpkill - kill a job in the mqueue */
  348.  
  349. static int dosmtpkill(int argc, char *argv[], void *p)
  350. {
  351.     char s[SLINELEN];
  352.     char *cp, c;
  353.  
  354.     sprintf (s, "%s/%s.lck", Mailqdir, argv[1]);
  355.     cp = strrchr (s, '.');
  356.     if (!access (s, 0)) {
  357.         Current->ttystate.echo = Current->ttystate.edit = 0;
  358.         c = keywait("Warning, the job is locked by SMTP. Remove (y/n)? ", 0);
  359.         Current->ttystate.echo = Current->ttystate.edit = 1;
  360.         if (c != 'y')
  361.             return 0;
  362.  
  363.         (void)unlink(s);
  364.     }
  365.  
  366.     strcpy(cp, ".wrk");
  367.     if (unlink(s))
  368.         tprintf("Job id %s not found\n", argv[1]);
  369.  
  370.     strcpy(cp, ".txt");
  371.     (void)unlink(s);
  372.     strcpy(cp, ".dly");
  373.     (void)unlink(s);
  374.  
  375.     return 0;
  376. }
  377.  
  378.  
  379. /*  dotimer - Set outbound spool scan interval */
  380.  
  381. static int dotimer(int argc, char *argv[], void *p)
  382. {
  383.     if (argc < 2) {
  384.         tprintf ("%lu/%lu\n",
  385.                  read_timer (&Smtpcli_t) / 1000L,
  386.                  dur_timer (&Smtpcli_t) / 1000L);
  387.         return 0;
  388.     }
  389.  
  390.     Smtpcli_t.func = (void (*) ()) smtptick;     /* what to call on timeout */
  391.     Smtpcli_t.arg = NULL;                         /* dummy value */
  392.     set_timer (&Smtpcli_t, atol (argv[1]) * 1000L);        /* set timer duration */
  393.     start_timer (&Smtpcli_t);                     /* and fire it up */
  394.  
  395.     return 0;
  396. }
  397.  
  398.  
  399. /*  dodelay - Set delay channel time */
  400.  
  401. static int dodelay(int argc, char *argv[], void *p)
  402. {
  403.     if (argc < 2) {
  404.         tprintf ("%lu\n", Delaytime);
  405.         return 0;
  406.     }
  407.  
  408.     Delaytime = atol (argv[1]);
  409.  
  410.     return 0;
  411. }
  412.  
  413.  
  414. /*    dowait -    Displays or sets the connection wait timeout. */
  415.  
  416. static int dowait(int argc, char *argv[], void *p)
  417. {
  418.     if (argc < 2) {
  419.         tprintf ("smtp connection timeout: %lu\n", connect_wait_val / 1000L);
  420.         return (0);
  421.     }
  422.  
  423.     connect_wait_val = atol (argv[1]) * 1000L;     /* set timeout                     */
  424.  
  425.     return (0);
  426. }
  427.  
  428.  
  429. static int smtpkick(int argc, char *argv[], void *p)
  430. {
  431.     int32 addr = 0;
  432.  
  433.     if (argc > 1 && (addr = resolve (argv[1])) == 0) {
  434.         tprintf (Badhost, argv[1]);
  435.         return 1;
  436.     }
  437.     log(-1, "smtpkick: resolve addr = %x ", (void *)addr); /* DEBUG */
  438.     smtptick ((void *) addr);
  439.     return 0;
  440. }
  441.  
  442.  
  443. /* This is the routine that gets called every so often to do outgoing
  444.  * mail processing. When called with a null argument, it runs the entire
  445.  * queue; if called with a specific non-zero IP address from the remote
  446.  * kick server, it only starts up sessions to that address.
  447.  */
  448.  
  449. static char smtptick_running = 0;
  450.  
  451. int smtptick(void *t) {
  452.  
  453.     if (smtptick_running != 0)
  454.         return (0);
  455.  
  456.     smtptick_running = 1;
  457.     if (newproc ("smtp_tick", 1024, smtptick_body, 0, t, NULL, 0) == NULLPROC)    {
  458.         start_timer (&Smtpcli_t);        /* wait a while */
  459.         smtptick_running = 0;
  460.     }
  461.  
  462.     return (0);
  463. }
  464.  
  465.  
  466. static void __stdargs smtptick_body (int unused, void *t, void *p)
  467. {
  468.     struct smtpcli *cb;
  469.     struct smtp_job *jp;
  470.     struct list *ap;
  471.     char tmpstring[LINELEN], wfilename[13], prefix[9];
  472.     char from[LINELEN], to[LINELEN];
  473.     char *cp, *cp1;
  474.     int32 destaddr, target, num_files;
  475.     FILE *wfile;
  476.  
  477.     target = (int32) t;
  478.  
  479.     if (Smtptrace > 5)
  480.         tprintf ("smtp daemon entered, target = %s\n", inet_ntoa (target));
  481.  
  482.     if (availmem () < Memthresh) {
  483.         /* Memory is tight, don't do anything */
  484.         /* Restart timer */
  485.         start_timer (&Smtpcli_t);
  486.         smtptick_running = 0;
  487.         return;
  488.     }
  489.  
  490.     /* First see how many there are now */
  491.  
  492.     num_files = 0;
  493.     for (filedir (Mailqueue, 0, wfilename); wfilename[0] != '\0';
  494.          filedir (Mailqueue, 1, wfilename))
  495.         num_files++;
  496.  
  497.     /* Try to deal with that many messages, no more or we may loop forever */
  498.  
  499.     for (filedir (Mailqueue, 0, wfilename); wfilename[0] != '\0' && num_files--;
  500.          filedir (Mailqueue, 1, wfilename))    {
  501.  
  502.         /* save the prefix of the file name which it job id */
  503.         cp = wfilename;
  504.         cp1 = prefix;
  505.         while (*cp && *cp != '.')
  506.             *cp1++ = *cp++;
  507.  
  508.         *cp1 = '\0';
  509.  
  510.         /* lock this file from the smtp daemon */
  511.         if (mlock (Mailqdir, prefix))
  512.             continue;
  513.  
  514.         /* Try to bring the job outof delay (in case it's in delay) */
  515.  
  516.         explock (Mailqdir, prefix, "dly", Delaytime);
  517.  
  518.         /* Check that it's not in delay */
  519.         if (mlock_suffix (Mailqdir, prefix, "dly")) {
  520.             rmlock (Mailqdir, prefix);
  521.             continue;
  522.         }
  523.         else
  524.             rmlock_suffix (Mailqdir, prefix, "dly");
  525.  
  526.         sprintf (tmpstring, "%s/%s", Mailqdir, wfilename);
  527.         if ((wfile = fopen (tmpstring, READ_TEXT)) == NULLFILE) {
  528.             /* probably too many open files */
  529.             (void) rmlock (Mailqdir, prefix);
  530.             /* continue to next message. The failure may be temporary */
  531.             continue;
  532.         }
  533.  
  534.         (void) fgets (tmpstring, LINELEN, wfile);/* read target host */
  535.         rip (tmpstring);
  536.  
  537.         if ((destaddr = mailroute (tmpstring, Ip_addr)) == 0)    {
  538.             fclose (wfile);
  539.             tprintf ("** smtp: Unknown address %s\n", tmpstring);
  540.             (void) rmlock (Mailqdir, prefix);
  541.             continue;
  542.         }
  543.  
  544.         if (target != 0 && destaddr != target)    {
  545.             fclose (wfile);
  546.             (void) rmlock (Mailqdir, prefix);
  547.             continue;                             /* Not the proper target of a kick */
  548.         }
  549.  
  550.         if ((cb = lookup (destaddr)) == NULLSMTPCLI) {
  551.             /* there are enough processes running already */
  552.             if (Smtpsessions >= Smtpmaxcli) {
  553.                 if (Smtptrace)
  554.                     tprintf ("smtp daemon: too many processes\n");
  555.                 fclose (wfile);
  556.                 (void) rmlock (Mailqdir, prefix);
  557.                 break;
  558.             }
  559.  
  560.             if ((cb = newcb()) == NULLSMTPCLI) {
  561.                 fclose(wfile);
  562.                 (void)rmlock(Mailqdir, prefix);
  563.                 break;
  564.             }
  565.  
  566.             cb->ipdest   = destaddr;
  567.             cb->destname = strdup(tmpstring);    /* implicit malloc                */
  568.             log(-1, "smtptick_body: strdup cb->destname = %x ", (void *)cb->destname); /* DEBUG */
  569.         }
  570.         else {
  571.             if (cb->lock) {
  572.                 /* This system is already is sending mail lets not
  573.                  * interfere with its send queue. */
  574.                 fclose (wfile);
  575.                 (void) rmlock (Mailqdir, prefix);
  576.                 continue;
  577.             }
  578.         }
  579.  
  580.         (void) fgets (from, LINELEN, wfile);     /* read from */
  581.         rip (from);
  582.         if ((jp = setupjob(cb, prefix, from)) == NULLJOB)    {
  583.             fclose(wfile);
  584.             rmlock(Mailqdir, prefix);
  585.             del_session(cb);
  586.             break;
  587.         }
  588.  
  589.         while (fgets(to, LINELEN, wfile) != NULLCHAR) {
  590.             rip(to);
  591.             if (addlist(&jp->to, to, DOMAIN) == NULLLIST) {
  592.                 fclose(wfile);
  593.                 del_session(cb);
  594.             }
  595.         log(-1, "smpttick_body: addlist jp->to = %x ", jp->to); /* DEBUG */
  596.         log(-1, "smpttick_body: addlist jp->to->val = %x ", jp->to->val); /* DEBUG */
  597.  
  598.         }
  599.         fclose(wfile);
  600.  
  601.         if (Smtptrace > 1) {
  602.             tprintf("queue job %s From: %s To:", prefix, from);
  603.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  604.                 tprintf(" %s", ap->val);
  605.             tprintf ("\n");
  606.         }
  607.  
  608.         if (smtpverbose != 0 && Smtptrace <= 1) {
  609.             tprintf ("Sending %s From: %s To:", prefix, from);
  610.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  611.                 tprintf (" %s", ap->val);
  612.             tprintf ("\n");
  613.         }
  614.     }
  615.  
  616.     /* start sending that mail */
  617.  
  618.     execjobs ();
  619.  
  620.     /* Restart timer */
  621.  
  622.     start_timer(&Smtpcli_t);
  623.     smtptick_running = 0;
  624.     return;
  625. }
  626.  
  627.  
  628. static int should_enter_delay(struct smtpcli *cb)
  629. {
  630.     resolve_mx (cb->destname);
  631.     log(-1, "should_enter_delay: resolve_mx cb->destname = %x ", (void *)cb->destname); /* DEBUG */
  632.     if (are_we_an_mx)
  633.         return 1;
  634.  
  635.     return 0;
  636. }
  637.  
  638.  
  639. void delay_job(int32 msgid)
  640. {
  641.     char t[20];
  642.  
  643.     if (Delaytime == 0)
  644.         /* Not using SMTP delay */
  645.         return;
  646.  
  647.     sprintf (t, "%lu", msgid);
  648.  
  649.     if (Smtptrace)
  650.         tprintf ("Delivery Failed: adding job %s to delay queue\n", t);
  651.  
  652.     mlock_suffix (Mailqdir, t, "dly");
  653. }
  654.  
  655. /* This is the master state machine that handles a single SMTP transaction.
  656.  * It is called with a queue of jobs for a particular host.
  657.  * The logic is complicated by the "Smtpbatch" variable, which controls
  658.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  659.  * SMTP commands are sent in one swell foop before waiting for any of
  660.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  661.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  662.  */
  663.  
  664. static void __stdargs smtp_send (int unused, void *cb1, void *p)
  665. {
  666.     struct smtpcli *cb;
  667.     struct list *tp;
  668.     struct sockaddr_in fsocket;
  669.     char *cp;
  670.     int rcode;
  671.     int rcpts;
  672.     int goodrcpt;
  673.     int i;
  674.     int init = 1;
  675.  
  676.     cb = (struct smtpcli *)cb1;
  677.     cb->lock = 1;
  678.     fsocket.sin_family         = AF_INET;
  679.     fsocket.sin_addr.s_addr = cb->ipdest;
  680.     fsocket.sin_port             = IPPORT_SMTP;
  681.  
  682.     cb->s = socket(AF_INET, SOCK_STREAM, 0);
  683.     sockmode(cb->s, SOCK_ASCII);
  684.     setflush(cb->s, -1);                /* We'll explicitly flush before reading */
  685.  
  686.     if (Smtptrace)
  687.         tprintf ("SMTP client Trying...\n");
  688.  
  689.     /* Run connect () under a timeout in case the destination is unreachable. */
  690.  
  691.     alarm(connect_wait_val);
  692.     if (connect (cb->s, (char *) &fsocket, SOCKSIZE) == 0) {
  693.         alarm (0L);
  694.         if (Smtptrace)
  695.             tprintf ("Connected\n");
  696.     }
  697.     else {
  698.         alarm(0L);
  699.         if (Delaytime && (cb->ipdest == Ip_addr || should_enter_delay(cb)))
  700.             delay_job(atol(cb->jobq->jobname));
  701.     else
  702.         if (Gateway != 0L) {
  703.             
  704.             /* Try sending it via the gateway, as long as it's not for us. */
  705.  
  706.             if (Smtptrace)
  707.                 tprintf ("SMTP client Trying gateway...\n");
  708.  
  709.             close_s(cb->s);
  710.             cb->ipdest = Gateway;
  711.             fsocket.sin_addr.s_addr = Gateway;
  712.             cb->s = socket(AF_INET, SOCK_STREAM, 0);
  713.             sockmode(cb->s, SOCK_ASCII);
  714.             setflush(cb->s, -1);
  715.             alarm(connect_wait_val);
  716.             
  717.             if (connect(cb->s, (char *) &fsocket, SOCKSIZE) != 0) {
  718.                 alarm(0L);
  719.                 cp = sockerr(cb->s);
  720.                 if (Smtptrace)
  721.                     tprintf("Connect failed: %s\n", cp != NULLCHAR ? cp : "");
  722.                 log(cb->s, "SMTP %s Connect failed: %s", psocket (&fsocket),
  723.                      cp != NULLCHAR ? cp : "");
  724.  
  725.                 goto quit;
  726.             }
  727.             else {
  728.                 alarm(0L);
  729.                 if (Smtptrace)
  730.                     tprintf ("Connected to Gateway\n");
  731.             }
  732.  
  733.         }
  734.         else {
  735.             cp = sockerr(cb->s);
  736.             if (Smtptrace)
  737.                 tprintf ("Connect failed: %s\n", cp != NULLCHAR ? cp : "");
  738.             log (cb->s, "SMTP %s Connect failed: %s", psocket(&fsocket),
  739.                                                                     cp != NULLCHAR ? cp : "");
  740.             goto quit;
  741.         }
  742.  
  743.     }
  744.  
  745.     if (!Smtpbatch) {
  746.         rcode = getresp (cb, 200);
  747.         if (rcode == -1 || rcode >= 400)
  748.             goto quit;
  749.  
  750.     }
  751.  
  752.     /* Say HELO */
  753.  
  754.     sendcmd(cb, "HELO %s\n", Hostname);
  755.  
  756.     if (!Smtpbatch) {
  757.         rcode = getresp(cb, 200);
  758.         if (rcode == -1 || rcode >= 400)
  759.             goto quit;
  760.     }
  761.  
  762.     do    {                                         /* For each message... */
  763.         /* if this file open fails, skip it */
  764.  
  765.         if ((cb->tfile = fopen(cb->tname, READ_TEXT)) == NULLFILE)
  766.             continue;
  767.  
  768.         /* Send MAIL and RCPT commands */
  769.  
  770.         sendcmd (cb, "MAIL FROM:<%s>\n", cb->jobq->from);
  771.         if (!Smtpbatch) {
  772.             rcode = getresp(cb, 200);
  773.             if (rcode == -1 || rcode >= 400)
  774.                 goto quit;
  775.         }
  776.  
  777.         rcpts = 0;
  778.         goodrcpt = 0;
  779.         for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next) {
  780.             sendcmd(cb, "RCPT TO:<%s>\n", tp->val);
  781.             if (!Smtpbatch) {
  782.                 rcode = getresp (cb, 200);
  783.                 if (rcode == -1)
  784.                     goto quit;
  785.  
  786.                 if (rcode < 400)
  787.                     goodrcpt = 1;                 /* At least one good */
  788.             }
  789.             rcpts++;
  790.         }
  791.  
  792.         /* Send DATA command */
  793.  
  794.         sendcmd(cb, "DATA\n");
  795.         if (!Smtpbatch) {
  796.             rcode = getresp(cb, 200);
  797.             if (rcode == -1 || rcode >= 400)
  798.                 goto quit;
  799.         }
  800.  
  801.         if (Smtpbatch)    {
  802.             /* Now wait for the responses to come back. The first time we
  803.              * do this, we wait first for the start banner and HELO
  804.              * response. In any case, we wait for the response to the MAIL
  805.              * command here. */
  806.              
  807.             for (i = init ? 3 : 1; i > 0; i--) {
  808.                 rcode = getresp(cb, 200);
  809.                 if (rcode == -1 || rcode >= 400)
  810.                     goto quit;
  811.             }
  812.             init = 0;
  813.  
  814.             /* Now process the responses to the RCPT commands */
  815.             
  816.             for (i = rcpts; i != 0; i--) {
  817.                 rcode = getresp (cb, 200);
  818.                 if (rcode == -1)
  819.                     goto quit;
  820.  
  821.                 if (rcode < 400)
  822.                     goodrcpt = 1;                 /* At least one good */
  823.  
  824.             }
  825.             
  826.             /* And finally get the response to the DATA command. Some
  827.              * servers will return failure here if no recipients are valid,
  828.              * some won't. */
  829.              
  830.             rcode = getresp (cb, 200);
  831.             if (rcode == -1 || rcode >= 400)
  832.                 goto quit;
  833.  
  834.             /* check for no good rcpt on the list */
  835.  
  836.             if (goodrcpt == 0) {
  837.                 sendcmd(cb, ".\n");             /* Get out of data mode */
  838.                 goto quit;
  839.             }
  840.         }
  841.  
  842.         /* Send the file. This also closes it */
  843.  
  844.         smtpsendfile(cb);
  845.  
  846.         /* Wait for the OK response */
  847.         rcode = getresp(cb, 200);
  848.         if (rcode == -1)
  849.             goto quit;
  850.  
  851.         if ((rcode >= 200 && rcode < 300) || rcode >= 500)    {
  852.  
  853.             /* if a good transfer or permanent failure remove job */
  854.  
  855.             if (cb->errlog != NULLLIST)
  856.                 retmail (cb);
  857.  
  858.             /* Unlink the textfile */
  859.  
  860.             (void) unlink (cb->tname);
  861.             (void) unlink (cb->wname);             /* unlink workfile */
  862.  
  863.             log(cb->s, "SMTP sent job %s To: %s From: %s",
  864.                  cb->jobq->jobname, cb->jobq->to->val, cb->jobq->from);
  865.  
  866.             if (smtpverbose != 0 && Smtptrace <= 1) {
  867.                 /* Show sending progress. */
  868.  
  869.                 tprintf("Sent %s\n", cb->jobq->jobname);
  870.             }
  871.         }
  872.  
  873.     } while (next_job(cb));
  874.  
  875. quit:
  876.     sendcmd(cb, "QUIT\n");
  877.     if (cb->errlog != NULLLIST) {
  878.         retmail (cb);
  879.         unlink (cb->wname);                             /* unlink workfile                 */
  880.         unlink (cb->tname);                             /* unlink text                     */
  881.     }
  882.  
  883.     close_s(cb->s);
  884.     if (cb->tfile != NULLFILE)
  885.         fclose(cb->tfile);
  886.  
  887.     cb->lock = 0;
  888.     del_session(cb);
  889. }
  890.  
  891.  
  892. /*  mlock - create mail lockfile                                                         */
  893.  
  894. int mlock(char *dir, char *id)
  895. {
  896.     return mlock_suffix (dir, id, "lck");
  897. }
  898.  
  899.  
  900. int mlock_suffix(char *dir, char *id, char *suffix)
  901. {
  902.     char lockname[LINELEN];
  903.     int fd;
  904.  
  905. #if defined(MSDOS) || defined(ATARI)
  906.     if (strlen (id) > 8)    {                             /* truncate long filenames */
  907.         id[8] = '\0';
  908.         if (id[7] == '/')
  909.             id[7] = '\0';
  910.  
  911.     }
  912. #endif
  913.     /* Try to create the lock file in an atomic operation */
  914.  
  915.     sprintf(lockname, "%s/%s.%s", dir, id, suffix);
  916.  
  917.     if ((fd = open(lockname, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1)
  918.         return -1;
  919.  
  920.     close(fd);
  921.     return 0;
  922. }
  923.  
  924.  
  925. /*  rmlock - Remove mail lockfile */
  926.  
  927. int rmlock(char *dir, char *id)
  928. {
  929.     return rmlock_suffix(dir, id, "lck");
  930. }
  931.  
  932.  
  933. int rmlock_suffix(char *dir, char *id, char *suffix)
  934. {
  935.     char lockname[LINELEN];
  936.  
  937. #if defined(MSDOS) || defined(ATARI)
  938.     if (strlen (id) > 8)    {                             /* truncate long filenames */
  939.         id[8] = '\0';
  940.         if (id[7] == '/')
  941.             id[7] = '\0';
  942.  
  943.     }
  944. #endif
  945.  
  946.     sprintf (lockname, "%s/%s.%s", dir, id, suffix);
  947.     return (unlink (lockname));
  948. }
  949.  
  950.  
  951. /*  del_session - Free the message struct and data */
  952.  
  953. static void del_session(struct smtpcli *cb)
  954. {
  955.     int i;
  956.     struct smtp_job *jp, *tp;
  957.  
  958.     if (cb == NULLSMTPCLI)
  959.         return;
  960.  
  961.     for (i = 0; i < MAXSESSIONS; i++)
  962.         if (cli_session[i] == cb) {
  963.             cli_session[i] = NULLSMTPCLI;
  964.             break;
  965.         }
  966.  
  967.     log(-1,"del_session: free cb->wname = %x ", (void *)cb->wname);  /* DEBUG */
  968.     free(cb->wname);
  969.     log(-1,"del_session: free cb->tname = %x ", (void *)cb->tname);  /* DEBUG */
  970.     free(cb->tname);
  971.     log(-1,"del_session: free cb->destname = %x ", (void *)cb->destname);  /* DEBUG */
  972.     free(cb->destname);
  973.  
  974.     for (jp = cb->jobq; jp != NULLJOB; jp = tp) {
  975.         tp = jp->next;
  976.         del_job(jp);
  977.     }
  978.  
  979.     del_list(cb->errlog);
  980.     log(-1,"del_session: free cb = %x ", (void *)cb);  /* DEBUG */
  981.     free((void *)cb);
  982.     Smtpsessions--;                                 /* number of connections active */
  983. }
  984.  
  985.  
  986. /*  del_job - Free smtp_job structure                                                    */
  987.  
  988. static void del_job(struct smtp_job *jp)
  989. {
  990.     if (*jp->jobname != '\0')
  991.         (void) rmlock(Mailqdir, jp->jobname);
  992.  
  993.     log(-1,"del_job: free jp->from = %x ", (void *)jp->from);  /* DEBUG */
  994.     free(jp->from);
  995.     del_list(jp->to);
  996.     log(-1,"del_job: free jp = %x ", (void *)jp);  /* DEBUG */
  997.     free((void *)jp);
  998. }
  999.  
  1000.  
  1001. /*  del_list - Delete a list of list structs */
  1002.  
  1003. void del_list(struct list *lp)
  1004. {
  1005.     struct list *tp, *tp1;
  1006.  
  1007.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  1008.         tp1 = tp->next;
  1009.         log(-1, "del_list: free tp->val = %x ", (void *)tp->val);  /* DEBUG */
  1010.         free(tp->val);
  1011.         log(-1, "del_list: free tp = %x ", (void *)tp);  /* DEBUG */
  1012.         free((char *) tp);
  1013.     }
  1014. }
  1015.  
  1016.  
  1017. /*  retmail - Stub for calling mdaemon to return message to sender */
  1018.  
  1019. static void retmail(struct smtpcli *cb)
  1020. {
  1021.     FILE *infile;
  1022.  
  1023.     if (Smtptrace > 5)
  1024.         tprintf("smtp job %s returned to sender\n", cb->wname);
  1025.  
  1026.     if ((infile = fopen(cb->tname, READ_TEXT)) == NULLFILE)
  1027.         return;
  1028.  
  1029.     mdaemon(infile, cb->jobq->from, cb->errlog, 1);
  1030.     fclose(infile);
  1031. }
  1032.  
  1033.  
  1034. /*  lookup - Look to see if a smtp control block exists for this ipdest */
  1035.  
  1036. static struct smtpcli *lookup(int32 destaddr)
  1037. {
  1038.     int i;
  1039.  
  1040.     for (i = 0; i < MAXSESSIONS; i++) {
  1041.         if (cli_session[i] == NULLSMTPCLI)
  1042.             continue;
  1043.  
  1044.         if (cli_session[i]->ipdest == destaddr)
  1045.             return cli_session[i];
  1046.     }
  1047.     return NULLSMTPCLI;
  1048. }
  1049.  
  1050.  
  1051. /*  newcb - create a new  smtp control block */
  1052.  
  1053. static struct smtpcli *newcb(void)
  1054. {
  1055.     int i;
  1056.     struct smtpcli *cb;
  1057.  
  1058.     for (i = 0; i < MAXSESSIONS; i++) {
  1059.         if (cli_session[i] == NULLSMTPCLI) {
  1060.             cb = (struct smtpcli *) calloc(1, sizeof (struct smtpcli));
  1061.             log(-1,"newcb: calloc cb = %x ", (void *)cb); /*DEBUG */
  1062.             cb->wname = malloc((unsigned) strlen (Mailqdir) + JOBNAME);
  1063.             log(-1,"newcb: malloc cb->wname = %x ", (void *)cb->wname); /* DEBUG */
  1064.             cb->tname = malloc((unsigned) strlen (Mailqdir) + JOBNAME);
  1065.             log(-1,"newcb: malloc cb->tname = %x ", (void *)cb->tname); /* DEBUG */
  1066.             cli_session[i] = cb;
  1067.             Smtpsessions++;                             /* number of connections active */
  1068.             
  1069.             return (cb);
  1070.         }
  1071.     }
  1072.     return NULLSMTPCLI;
  1073. }
  1074.  
  1075.  
  1076. static void execjobs(void)
  1077. {
  1078.     int i;
  1079.     struct smtpcli *cb;
  1080.  
  1081.     for (i = 0; i < MAXSESSIONS; i++) {
  1082.         cb = cli_session[i];
  1083.         if (cb == NULLSMTPCLI)
  1084.             continue;
  1085.  
  1086.         if (cb->lock)
  1087.             continue;
  1088.  
  1089.         sprintf(cb->tname, "%s/%s.txt", Mailqdir, cb->jobq->jobname);
  1090.         sprintf(cb->wname, "%s/%s.wrk", Mailqdir, cb->jobq->jobname);
  1091.  
  1092.         newproc("smtp_send", 1024, smtp_send, 0, cb, NULL, 0);
  1093.  
  1094.         if (Smtptrace)
  1095.             tprintf("Trying Connection to %s\n", inet_ntoa (cb->ipdest));
  1096.     }
  1097. }
  1098.  
  1099.  
  1100. /*  smtp_job - Add this job to control block queue */
  1101.  
  1102. static struct smtp_job *setupjob(struct smtpcli *cb, char *id, char *from)
  1103. {
  1104.     struct smtp_job *p1, *p2;
  1105.  
  1106.     p1 = (struct smtp_job *) calloc(1, sizeof (struct smtp_job));
  1107.     log(-1, "setupjob: calloc p1 = %x ", (void *)p1); /* DEBUG */
  1108.  
  1109.     p1->from = strdup(from);                        /* implicit malloc                */
  1110.     log(-1, "setupjob: strdup p1->from = %x ", (void *)p1->from); /* DEBUG */
  1111.     strcpy (p1->jobname, id);
  1112.     
  1113.     /* now add to end of jobq */
  1114.  
  1115.     if ((p2 = cb->jobq) == NULLJOB)
  1116.         cb->jobq = p1;
  1117.     else {
  1118.         while (p2->next != NULLJOB)
  1119.             p2 = p2->next;
  1120.  
  1121.         p2->next = p1;
  1122.     }
  1123.  
  1124.     return p1;
  1125. }
  1126.  
  1127.  
  1128. /*  next_job - Called to advance to the next job */
  1129.  
  1130. static int next_job(struct smtpcli *cb)
  1131. {
  1132.     struct smtp_job *jp;
  1133.  
  1134.     jp = cb->jobq->next;
  1135.     del_job(cb->jobq);
  1136.     
  1137.     /* remove the error log of previous message */
  1138.  
  1139.     del_list(cb->errlog);
  1140.     cb->errlog = NULLLIST;
  1141.     cb->jobq = jp;
  1142.     if (jp == NULLJOB)
  1143.         return 0;
  1144.  
  1145.     sprintf(cb->tname, "%s/%s.txt", Mailqdir, jp->jobname);
  1146.     sprintf(cb->wname, "%s/%s.wrk", Mailqdir, jp->jobname);
  1147.  
  1148.     if (Smtptrace > 5)
  1149.         tprintf("sending job %s\n", jp->jobname);
  1150.  
  1151.     return 1;
  1152.  
  1153. }
  1154.  
  1155.  
  1156. /*  mailroute - Mail routing function. */
  1157.  
  1158. int32 mailroute(char *dest, int32 gateway)
  1159. {
  1160.     int32 destaddr;
  1161.  
  1162.     /* Test for domain literal first. */
  1163.  
  1164.     if (*dest == '[')
  1165.         return (aton(dest));
  1166.  
  1167. /* If the destination is this site, then *don't* go through a mail
  1168.  * server (MX site)
  1169.  */
  1170.  
  1171.     if (stricmp(dest, Hostname) == 0)
  1172.         if ((destaddr = resolve(dest)) != 0) {
  1173.             log(-1, "next_job: resolve destaddr = %x ", (void *)destaddr); /* DEBUG */
  1174.             return destaddr;
  1175.         }
  1176.     log(-1, "next_job: resolve destaddr = %x ", (void *)destaddr); /* DEBUG */    
  1177.             
  1178.  
  1179.     /* look up address or use the gateway */
  1180.  
  1181.     destaddr = resolve_mx(dest);
  1182.     log(-1, "next_job: resolve_mx destaddr = %x ", (void *)destaddr); /* DEBUG */
  1183.     
  1184.     if (destaddr == 0 && (destaddr = resolve (dest)) == 0) {
  1185. #ifdef DSERVER
  1186.         if (zone_filename (dest, NULL))
  1187.             destaddr = gateway;
  1188.         else
  1189. #endif
  1190.         if (Gateway != 0)
  1191.             destaddr = Gateway;                    /* Use the gateway                      */
  1192.     }
  1193.  
  1194.     return destaddr;
  1195. }
  1196.  
  1197.  
  1198. /*  logerr - Save line in error list */
  1199.  
  1200. static void logerr(struct smtpcli *cb, char *line)
  1201. {
  1202.     struct list *lp, *tp;
  1203.  
  1204.     tp = (struct list *)calloc(1, sizeof (struct list));
  1205.     log(-1, "logerr: calloc tp = %x ", (void *)tp); /* DEBUG */
  1206.     tp->val = strdup(line);                        /* implicit malloc                    */
  1207.     log(-1, "logerr: strdup tp->val = %x ", (void *)tp->val); /* DEBUG */
  1208.     /* find end of list */
  1209.     if ((lp = cb->errlog) == NULLLIST)
  1210.         cb->errlog = tp;
  1211.     else {
  1212.         while (lp->next != NULLLIST)
  1213.             lp = lp->next;
  1214.  
  1215.         lp->next = tp;
  1216.     }
  1217. }
  1218.  
  1219.  
  1220. static int smtpsendfile(struct smtpcli *cb)
  1221. {
  1222.     int error = 0;
  1223.  
  1224.     strcpy(cb->buf, "\n");
  1225.  
  1226.     while (fgets (cb->buf, sizeof (cb->buf), cb->tfile) != NULLCHAR) {
  1227.  
  1228.         if (cb->buf[0] == '.')                        /* handle dot transparency        */
  1229.             usputc(cb->s,'.');                        /* add extra '.'                     */
  1230.  
  1231.         usputs (cb->s, cb->buf);
  1232.     }
  1233.  
  1234.     fclose(cb->tfile);
  1235.     cb->tfile = NULLFILE;
  1236.  
  1237.     /* Send the end-of-message command */
  1238.  
  1239.     if (cb->buf[strlen (cb->buf) - 1] == '\n')
  1240.         sendcmd(cb, ".\n");
  1241.     else
  1242.         sendcmd(cb, "\n.\n");
  1243.  
  1244.     return error;
  1245. }
  1246.  
  1247.  
  1248. /*  sendcmd - Do a printf() on the socket with optional local tracing */
  1249.  
  1250. static void sendcmd(struct smtpcli * cb, char *fmt,...)
  1251. {
  1252.     va_list args;
  1253.  
  1254.     va_start(args, fmt);
  1255.     if (Smtptrace)    {
  1256.         vsprintf(cb->buf, fmt, args);
  1257.         tprintf("smtp sent: %s", cb->buf);
  1258.     }
  1259.  
  1260.     vsprintf(cb->buf, fmt, args);
  1261.     usputs(cb->s, cb->buf);
  1262.     va_end(args);
  1263. }
  1264.  
  1265.     
  1266. /*  getresp - Wait for, read & display server response. Return the result code. */
  1267.  
  1268. static int getresp(struct smtpcli *cb, int mincode)
  1269. {
  1270.     int rval;
  1271.     char line[LINELEN];
  1272.  
  1273.     usflush (cb->s);
  1274.     for (;;)    {
  1275.         /* Get line */
  1276.         if (recvline(cb->s, line, LINELEN) == -1) {
  1277.             rval = -1;
  1278.             break;
  1279.         }
  1280.  
  1281.         rip(line);                                 /* Remove cr/lf */
  1282.         rval = atoi(line);
  1283.  
  1284.         if (Smtptrace)
  1285.             tprintf("smtp recv: %s\n", line);    /* Display to user                   */
  1286.  
  1287.         if (rval >= 500) {                            /* Save permanent error replies */
  1288.             char tmp[LINELEN];
  1289.  
  1290.             if (cb->errlog == NULLLIST) {
  1291.                 sprintf(tmp, "While talking to %s:",
  1292.                          cb->destname);
  1293.                 logerr(cb, tmp);
  1294.             }
  1295.  
  1296.             if (cb->buf[0] != '\0') {                    /* save offending command */
  1297.                 rip(cb->buf);
  1298.                 sprintf(tmp, ">>> %s", cb->buf);
  1299.                 logerr(cb, tmp);
  1300.                 cb->buf[0] = '\0';
  1301.             }
  1302.  
  1303.             sprintf(tmp, "<<< %s", line);
  1304.             logerr(cb, tmp);                                 /* save the error reply     */
  1305.         }
  1306.  
  1307.         /* Messages with dashes are continued */
  1308.  
  1309.         if (line[3] != '-' && rval >= mincode)
  1310.             break;
  1311.     }
  1312.     
  1313.     return rval;
  1314. }
  1315.  
  1316.  
  1317. static int doverbose(int argc, char *argv[], void *p)
  1318. {
  1319.     return setbool(&smtpverbose, "SMTP verbose mode", argc, argv);
  1320. }
  1321.  
  1322.  
  1323. unsigned long golden_ymdhms(long year, long month, long day, long hour, long minute, long second)
  1324. {
  1325.     long result = 365L * year + day + 31L * (month - 1);
  1326.  
  1327.     if (month < 3)
  1328.         result += (year - 1L) / 4L - (75L * ((year - 1) / 100 + 1)) / 100L;
  1329.     else
  1330.         result = result - (40L * month + 230L) / 100L + year / 4L - (75L * (year / 100 + 1)) / 100L;
  1331.  
  1332.     result *= 86400L;
  1333.     result += 3600 * hour;
  1334.     result += 60 * minute;
  1335.     result += second;
  1336.  
  1337.     return result;
  1338. }
  1339.  
  1340.  
  1341. static int explock(char *dir, char *pre, char *suf, int32 age)
  1342. {
  1343.     union FILE_TIME {
  1344.         struct ftime ft;
  1345.         unsigned int ft_int[2];
  1346.     }  file_time;
  1347.  
  1348.     struct ffblk fileinfo;
  1349.     struct tm *tm_now;
  1350.     time_t t_now;
  1351.     char t[80];
  1352.     unsigned long now, fage, difference;
  1353.  
  1354.     sprintf(t, "%s/%s.%s", dir, pre, suf);
  1355.     if (findfirst (t, &fileinfo, 0) == -1)
  1356.         return 1;
  1357.  
  1358.     if (Delaytime == 0)
  1359.         return !unlink (t);
  1360.  
  1361.     t_now  = time(NULL);
  1362.     tm_now = localtime(&t_now);
  1363.     now = golden_ymdhms(tm_now->tm_year + 1900, tm_now->tm_mon + 1,
  1364.                          tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min,
  1365.                          tm_now->tm_sec);
  1366.     file_time.ft_int[0] = fileinfo.ff_ftime;
  1367.     file_time.ft_int[1] = fileinfo.ff_fdate;
  1368.     fage = golden_ymdhms (file_time.ft.ft_year + 1980, file_time.ft.ft_month,
  1369.              file_time.ft.ft_day, file_time.ft.ft_hour, file_time.ft.ft_min,
  1370.                           file_time.ft.ft_tsec * 2);
  1371.     difference = now - fage;
  1372.     if (difference >= Delaytime)
  1373.         return !unlink(t);
  1374.  
  1375.     return 0;
  1376. }
  1377.  
  1378.